using System;
using System.Threading;
using System.Net.Sockets;
using Microsoft.SPOT.Messaging;
using System.Net;
using Microsoft.SPOT.Net.NetworkInformation;
using Microsoft.SPOT;
using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
//using GHIElectronics.NETMF.Hardware;
//using GHIElectronics.NETMF.Net;
//using GHIElectronics.NETMF.Net.Sockets;
//using GHIElectronics.NETMF.Net.NetworkInformation;
//using Socket = GHIElectronics.NETMF.Net.Sockets.Socket;
//using GHIElectronics.NETMF.FEZ;

public class NetBios2 : IDisposable
{
    public string MyNetBiosName { get; set; }
    private Thread NBThread;

    /// <summary>
    /// Create a Netbios socket Thread
    /// </summary>
    /// <param name="MyName">Name to answer to</param>
    public NetBios2(string MyName)
    {
        MyNetBiosName = MyName;
        NBThread = new Thread(NetBiosThread);
        NBThread.Start();
    }

    /// <summary>
    /// Close this Netbios class
    /// </summary>
    public void Dispose()
    {
        try // Close NetBios Thread
        {
            NBThread.Abort();
            DateTime timeoutAt = DateTime.Now.AddSeconds(10);
            while (NBThread.ThreadState != ThreadState.Aborted
                    && DateTime.Now < timeoutAt) Thread.Sleep(100);
        }
        catch { }
        NBThread = null;
    }

    /// <summary>
    /// Thread listening for Netbios Name Querries
    /// </summary>
    private void NetBiosThread()
    {
        while (true)
        {
            Socket serverSocket = null;
            try
            {
                // Listen to broadcasts on UDP port 137 (NETBIOS)
                serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                System.Net.EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 137);
                serverSocket.Bind(remoteEndPoint);

                if (serverSocket.Poll(-1, SelectMode.SelectRead))
                {
                    string NameQuery;
                    char c;
                    int i;
                    byte[] inBuf = new byte[serverSocket.Available];

                    serverSocket.ReceiveFrom(inBuf, ref remoteEndPoint);
                    if ((inBuf[2] >> 3) == 0) // This is a Name Query
                    {
                        NameQuery = "";
                        for (i = 0; i < 15; i++) // Decode Name looked up
                        {
                            c = (char)(((inBuf[(i * 2) + 13] - 'A') << 4) | (inBuf[(i * 2) + 14] - 'A'));
                            if (c == ' ') break;
                            NameQuery += c;
                        }
                        if (NameQuery == MyNetBiosName.ToUpper()) // This is us !
                        {
                            byte[] outBuf = new byte[62];
                            Array.Clear(outBuf, 0, 62);
                            outBuf[0] = inBuf[0]; outBuf[1] = inBuf[1]; // trnid                               
                            outBuf[2] = 0x85; outBuf[7] = 0x01; outBuf[12] = 0x20;
                            outBuf[47] = 0x20; // RR_TYPE: NB
                            outBuf[49] = 0x01; // RR_CLASS: IN
                            outBuf[51] = 0x0f; outBuf[52] = 0x0f; outBuf[53] = 0x0f;
                            outBuf[55] = 0x06; // RDLENGTH
                            outBuf[56] = 0x60; // NB_FLAGS
                            Array.Copy(inBuf, 13, outBuf, 13, 32);

                            var ipAddr = Microsoft.SPOT.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()[0].IPAddress.ToCharArray();

                            //Array.Copy(NetworkInterface.IPAddress, 0, outBuf, 58, 4);
                            Array.Copy(ipAddr, 0, outBuf, 58, 4);
                            serverSocket.SendTo(outBuf, remoteEndPoint);
                            Debug.Print("Replied a NETBIOS NAME QUERY from " + remoteEndPoint.ToString());
                        }
                    }
                    serverSocket.Close();
                }
            }
            catch { try { serverSocket.Close(); } catch { } }
        }
    }
}